package com.auxgroup.smarthome.inner.service;

import cn.jiguang.common.resp.BaseResult;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.schedule.ScheduleResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auxgroup.bridge.app.inner.vo.AppUserPushVo;
import com.auxgroup.bridge.business.inner.dto.AppPushTemplateDto;
import com.auxgroup.bridge.business.inner.vo.AppPushTemplateVo;
import com.auxgroup.jpush.JpushService;
import com.auxgroup.jpush.entity.JpushEntity;
import com.auxgroup.smarthome.BeanUtils;
import com.auxgroup.smarthome.inner.entity.AppPushTemplateEntity;
import com.auxgroup.smarthome.inner.entity.PushRecordEntity;
import com.auxgroup.smarthome.inner.entity.TemplateConditionBean;
import com.auxgroup.smarthome.inner.repo.AppPushTemplateRepo;
import com.auxgroup.smarthome.inner.repo.AppPushTemplateRepoSpec;
import com.auxgroup.smarthome.inner.repo.PushRecordEntityRepo;
import com.auxgroup.smarthome.syscode.BusinessCode;
import com.auxgroup.smarthome.utils.PageContent;
import com.auxgroup.smarthome.utils.PageUtils;
import com.auxgroup.smarthome.utils.common.LOG;
import com.auxgroup.smarthome.web.ApiResponse;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;

/**
 * Created by niuGuangzhe on 2017/8/7.
 */
@Service
public class AppPushTemplateService {
    @Autowired
    private AppPushTemplateRepo appPushTemplateRepo;

    @Autowired
    private JpushService jpushService;

    @Autowired
    private AppUserDBService appUserDBInnerService;

    @Autowired
    private PushRecordEntityRepo pushRecordEntityRepo;

    /**
     * 查找推送列表
     *
     * @param keyword
     * @param pushTimeStart
     * @param pushTimeEnd
     * @param progress
     * @param page
     * @param size
     * @return
     */
    public ApiResponse<PageContent<AppPushTemplateVo>> findAppPushTemplate(String keyword,
                                                                           Date pushTimeStart,
                                                                           Date pushTimeEnd,
                                                                           Integer progress,
                                                                           Integer page,
                                                                           Integer size) {
        Sort sort = new Sort(Sort.Direction.DESC, "pushTime");
        Pageable pageable = new PageRequest(page, size, sort);
        Page<AppPushTemplateEntity> entities = appPushTemplateRepo.findAll(AppPushTemplateRepoSpec.
                findByUncertainParameters(keyword, pushTimeStart, pushTimeEnd, progress), pageable);
        Page<AppPushTemplateVo> vos = new PageUtils(AppPushTemplateVo.class, entities).buildVosPage();
        return ApiResponse.ok((new PageContent<AppPushTemplateVo>(vos)));

    }

    /**
     * 新增推送模板
     *
     * @param dto
     * @return
     */
    public ApiResponse addAppPushTemplate(AppPushTemplateDto dto) {
        if (dto.getPushType() == 1 && dto.getPushTime() == null)
            return ApiResponse.prompt(BusinessCode.APP_PUSH_TEMPLATE_TIME_NULL);
        if (dto.getPushType() == 1 && dto.getPushTime() != null &&
                dto.getPushTime().getTime() < System.currentTimeMillis())
            return ApiResponse.prompt(BusinessCode.APP_PUSH_TEMPLATE_TIME_EXPIRED);
        if (dto.getPushType() != 1)
            dto.setPushTime(null);

        resetAdCondition(dto);
        AppPushTemplateEntity entity = AppPushTemplateEntity.translateToEntity(dto, 0);
        entity = appPushTemplateRepo.save(entity);
        return entity != null ? ApiResponse.ok(entity) : ApiResponse.prompt(BusinessCode.FAIL);

    }

    /**
     * 修改推送模板
     *
     * @param templateId
     * @param dto
     * @return
     */
    public ApiResponse updateAppPushTemplate(String templateId, AppPushTemplateDto dto) {
        AppPushTemplateEntity entity = appPushTemplateRepo.findByTemplateIdAndStatusLessThan(templateId, 1);
        if (entity == null) {
            return ApiResponse.prompt(BusinessCode.APP_PUSH_TEMPLATE_NOT_EXIST);
        }
        if (dto.getPushType() == 1 && dto.getPushTime() == null)
            return ApiResponse.prompt(BusinessCode.APP_PUSH_TEMPLATE_TIME_NULL);
        if (dto.getPushType() == 1 && dto.getPushTime() != null &&
                dto.getPushTime().getTime() < System.currentTimeMillis())
            return ApiResponse.prompt(BusinessCode.APP_PUSH_TEMPLATE_TIME_EXPIRED);
        if (dto.getPushType() != 1)
            dto.setPushTime(null);

        resetAdCondition(dto);
        entity = BeanUtils.copyAttrs(entity, dto);
        entity = appPushTemplateRepo.save(entity);
        return entity != null ? ApiResponse.ok(entity) : ApiResponse.prompt(BusinessCode.FAIL);
    }

    /**
     * 逻辑删除推送模板
     *
     * @param templateId 主键
     * @return
     */
    public ApiResponse deleteAppPushTemplate(String templateId) {
        int influencesCount = appPushTemplateRepo.logicallyDelete(templateId, 2);
        return influencesCount > 0 ? ApiResponse.prompt(BusinessCode.SC_OK) : ApiResponse.prompt(BusinessCode.FAIL);
    }

    /**
     * 推送服务
     *
     * @param templateId 主键
     * @return
     */
    public ApiResponse<BaseResult> pushToPaas(String templateId) {
        AppPushTemplateEntity entity = appPushTemplateRepo.findByTemplateIdAndStatusLessThan(templateId, 1);
        if (entity == null) {
            return ApiResponse.prompt(BusinessCode.APP_PUSH_TEMPLATE_NOT_EXIST);
        }
        TemplateConditionBean condition = JSON.parseObject(entity.getTemplateCondition(), TemplateConditionBean.class);
        ApiResponse<List<AppUserPushVo>> listApiResponse = appUserDBInnerService.filterUsers(condition.getGender(), condition.getCitys());
        if (listApiResponse.getCode() != 0 && listApiResponse.getCode() != 200) {
            return ApiResponse.prompt(listApiResponse.getCode().toString(), listApiResponse.getMessage());
        }
        List<AppUserPushVo> appUserPushVoList = listApiResponse.getData();
        sendAsync(appUserPushVoList, entity);
        return ApiResponse.prompt(BusinessCode.SC_OK);
    }

    /**
     * 推送服务new
     *
     * @param templateId 主键
     * @return
     */
    public ApiResponse<BaseResult> pushToPaasNew(String templateId) {
        AppPushTemplateEntity entity = appPushTemplateRepo.findByTemplateIdAndStatusLessThan(templateId, 1);
        if (entity == null) {
            return ApiResponse.prompt(BusinessCode.APP_PUSH_TEMPLATE_NOT_EXIST);
        }
        TemplateConditionBean condition = JSON.parseObject(entity.getTemplateCondition(), TemplateConditionBean.class);
        ApiResponse<List<AppUserPushVo>> listApiResponse = appUserDBInnerService.filterUsers(condition);
        if (listApiResponse.getCode() != 0 && listApiResponse.getCode() != 200) {
            return ApiResponse.prompt(listApiResponse.getCode().toString(), listApiResponse.getMessage());
        }
        List<AppUserPushVo> appUserPushVoList = listApiResponse.getData();
        sendAsyncNew(appUserPushVoList, entity);
        return ApiResponse.prompt(BusinessCode.SC_OK);
    }


    /**
     * 异步发送推送
     *
     * @param appUserPushVoList
     * @param entity
     */
    private void sendAsync(List<AppUserPushVo> appUserPushVoList, AppPushTemplateEntity entity) {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                LOG.info(this, "需要推送" + appUserPushVoList.size() + "客户");
                int successNum = 0;
                for (Iterator<AppUserPushVo> iterator = appUserPushVoList.iterator(); iterator.hasNext(); ) {
                    AppUserPushVo appUserPushVo = iterator.next();
                    String templateContent = entity.getTemplateContent();
                    if (templateContent.indexOf("${username}") >= 0) {
                        String content = "";
                        if (StringUtils.isBlank(appUserPushVo.getNickName())) {
                            content = appUserPushVo.getPhone();
                        } else {
                            content = appUserPushVo.getNickName();
                        }
                        templateContent = templateContent.replaceAll("\\$\\{username}", content);
                    }
                    if (templateContent.indexOf("${phone}") >= 0) {
                        templateContent = templateContent.replaceAll("\\$\\{phone}", appUserPushVo.getPhone());
                    }
                    JpushEntity jpushEntity = entity.translateToJPushEntity();
                    jpushEntity.setJpushMessage(templateContent);
                    jpushEntity.setCategory("0");
                    BaseResult result = jpushService.pushInfoSingle(jpushEntity, appUserPushVo.getPhone());
                    if (null != result && result instanceof PushResult) {
                        if (((PushResult) result).statusCode == 0) {
                            successNum++;
                            //添加逻辑 把推送记录入库保存 add by lixiaoxiao 20171012
                            PushRecordEntity pushRecordEntity = new PushRecordEntity(jpushEntity, appUserPushVo.getUid(),
                                    LocalDateTime.now().toString().replace("T", " "));
                            pushRecordEntityRepo.save(pushRecordEntity);
                        }
                    } else if (null != result && result instanceof ScheduleResult) {
                        successNum++;
                        //添加逻辑 把推送记录入库保存 add by lixiaoxiao 20171012
                        PushRecordEntity pushRecordEntity = new PushRecordEntity(jpushEntity, appUserPushVo.getUid(),
                                LocalDateTime.now().toString().replace("T", " "));
                        pushRecordEntityRepo.save(pushRecordEntity);
                    }
                }
                LOG.info(this, "成功推送" + successNum + "条");
                //如果是立即推送，更新推送时间
                if (0 == entity.getPushType()) {
                    entity.setPushTime(new Date());
                }
                entity.setStatus(1);//已发送
                appPushTemplateRepo.save(entity);
                return "push success!";
            }
        }, executor);
        //采用lambada的实现方式
        future.thenAccept(e -> executor.shutdown());
    }


    /**
     * 异步发送推送new
     *
     * @param appUserPushVoList
     * @param entity
     */
    private void sendAsyncNew(List<AppUserPushVo> appUserPushVoList, AppPushTemplateEntity entity) {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                LOG.info(this, "需要推送" + appUserPushVoList.size() + "客户");
                int successNum = 0;
                JpushEntity jpushEntity = entity.translateToJPushEntity();
                jpushEntity.setCategory("0");
                List<String> phoneList = new ArrayList<>();
                List<String> uidList = new ArrayList<>();
                for (AppUserPushVo appUserPushVo : appUserPushVoList) {
                    phoneList.add(appUserPushVo.getPhone());
                    uidList.add(appUserPushVo.getUid());
                }
                int batchNum = 500;
                int size = phoneList.size();
                int loop = (size + batchNum - 1) / batchNum;
                for (int i = 0; i < loop; i++) {
                    int startIndex = i * batchNum;
                    int endIndex = (i + 1) * batchNum > size ? size : (i + 1) * batchNum;
                    List<String> subuid = uidList.subList(startIndex, endIndex);
                    List<String> subphone = phoneList.subList(startIndex, endIndex);
                    BaseResult result = jpushService.pushInfo(jpushEntity, subphone);
                    if (null != result && result instanceof PushResult) {
                        if (((PushResult) result).statusCode == 0) {
                            successNum = successNum + (endIndex - startIndex);
                            //添加逻辑 把推送记录入库保存 add by wujianlong 20180612
                            List<PushRecordEntity> pushRecordEntities = new ArrayList<>();
                            for (String uid : subuid) {
                                pushRecordEntities.add(new PushRecordEntity(jpushEntity, uid,
                                        LocalDateTime.now().toString().replace("T", " ")));
                            }
                            pushRecordEntityRepo.save(pushRecordEntities);
                        }
                    } else if (null != result && result instanceof ScheduleResult) {
                        successNum = successNum + (endIndex - startIndex);
                        //添加逻辑 把推送记录入库保存 add by wujianlong 20180612
                        List<PushRecordEntity> pushRecordEntities = new ArrayList<>();
                        for (String uid : subuid) {
                            pushRecordEntities.add(new PushRecordEntity(jpushEntity, uid,
                                    LocalDateTime.now().toString().replace("T", " ")));
                        }
                        pushRecordEntityRepo.save(pushRecordEntities);
                    }
                }

                LOG.info(this, "成功推送" + successNum + "条");
                //如果是立即推送，更新推送时间
//                if (0 == entity.getPushType()) {
//                    entity.setPushTime(new Date());
//                }
//                entity.setStatus(1);//已发送
//                appPushTemplateRepo.save(entity);
                return "push success!";
            }
        }, executor);
        //采用lambada的实现方式
        future.thenAccept(e -> executor.shutdown());
    }


    /**
     * 根据adCondition设置sorceValue
     *
     * @param dto
     */
    public void resetAdCondition(AppPushTemplateDto dto) {
        String adCondition = dto.getAdCondition();
        if (StringUtils.isBlank(adCondition)) {
            dto.setAdCondition("{\"local\":\"\",\"sourceValue\":\"\",\"productPageUrl\":\"\",\"productPageType\":\"\",\"platform\":\"\",\"sourceType\":\"\"}");
            return;
        }
        JSONObject jsonObject = JSONObject.parseObject(adCondition);

        String local=jsonObject.getString("local");
        String productPageUrl = jsonObject.getString("productPageUrl");
        String productPageType = jsonObject.getString("productPageType");
        String platform = jsonObject.getString("platform");
        String sourceType = jsonObject.getString("sourceType");
        String sourceValue="";
        if (sourceType.equals("schema")) {
            switch (platform) {
                case "jd":
                    sourceValue = productPageType.equals("商品详情页") ? getJdDetailSourceValue(productPageUrl) : getJdActivSourceValue(productPageUrl);
                    break;
                //todo 添加其他平台的sourceValue
//                case "taobao":
//                    schema = dto.getProductPageType().equals("商品详情页") ? String.format("taobao详情页%s", url) : String.format("taobao活动页%s", url);
//                    break;

            }
        } else if (sourceType.equals("local")) {
            sourceValue = getSourceValue(local);
        }
        jsonObject.put("sourceValue", sourceValue);
        dto.setAdCondition(jsonObject.toJSONString());
    }



    /**
     * 获取jd商品详情页的sourceValue
     *
     * @param skuId
     * @return
     */
    public String getJdDetailSourceValue(String skuId) {
        String model = String.format("{\"sourceValue\":\"0_productDetail_97\",\"des\":\"productDetail\",\"skuId\":\"%s\",\"category\":\"jump\",\"sourceType\":\"PCUBE_CHANNEL\"}", skuId);
        String params = java.net.URLEncoder.encode(model);
        String schema = String.format("openapp.jdmobile://virtual?params=%s", params);
        return schema;
    }


    /**
     * 获取jd商品活动页的sourceValue
     *
     * @param url
     * @return
     */
    public String getJdActivSourceValue(String url) {
        String model = String.format("{\"category\": \"jump\",\"des\": \"m\",\"sourceValue\": \"babel-act\",\"sourceType\": \"babel\",\"url\": \"%s\",\"M_sourceFrom\": \"h5auto\",\"msf_type\": \"adod\"}", url);
        String params = java.net.URLEncoder.encode(model);
        String schema = String.format("openapp.jdmobile://virtual?params=%s", params);
        return schema;
    }

    /**
     * 获取local的sourceValue
     *
     * @param url
     * @return
     */
    public String getSourceValue(String url) {
        String params = java.net.URLEncoder.encode(url);
        String sourceValue = String.format("webview?url=%s", params);
        return sourceValue;
    }

}
